#include "main.h"
#include <string.h>
#include "ssd1306_app.h"
#include "nrf_gpio.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf_drv_spi.h"
#include "nrf_drv_config.h"


static const nrf_drv_spi_t m_spi_master = NRF_DRV_SPI_INSTANCE(0);
//#define USE_LOGO_BUFF
// the memory buffer for the LCD
#ifdef USE_LOGO_BUFF
uint8_t buffer[128 * 8] = {
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,
      0xE0,0xF0,0xF0,0xF8,0x78,0x38,0x3C,0x3C,0x1C,0x1C,0x0E,0x0E,0x06,0x06,0x02,0x02,
      0x00,0x02,0x06,0x06,0x0E,0x0E,0x1E,0x1C,0x3C,0x3C,0x78,0x78,0xF8,0xF0,0xF0,0xE0,
      0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0xF0,0xFC,0x7E,0x3E,0x1F,0x0F,0x0F,0x0F,
      0x0F,0x03,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,
      0x02,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x0F,
      0x0F,0x0F,0x1F,0x1F,0x3F,0x7E,0xFC,0xF8,0xE0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x80,0x38,0x1E,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x08,0x00,0x02,
      0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xE0,0x63,0x07,0x0F,0xFE,0xF8,0x00,
      0x00,0xF8,0xFE,0x0F,0x07,0x67,0xE0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
      0x01,0x04,0x00,0x00,0x40,0x00,0x00,0x01,0x03,0x07,0x0F,0x1E,0x38,0xE0,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0xFC,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x3E,0xFF,0xFF,0xC3,0x80,0x00,0x00,0x00,0xFF,0xFF,0x00,
      0x00,0xFF,0xFF,0x00,0x00,0x00,0x80,0xC1,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xFF,0xFE,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x7F,0xFF,0xFF,0xFC,0xE0,0x80,0x00,0x00,0x00,0x01,0x40,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC1,0x83,0x87,0x87,0x86,0x8F,0x9F,0x9F,0x00,
      0x00,0x9F,0x9F,0x8F,0x86,0x87,0x87,0x83,0xC3,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x80,0xC0,0xF8,0xFF,0xFF,0x7F,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x03,0x1F,0x7F,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x04,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,
      0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xF1,0xFF,0xFF,0x7F,0x1F,0x03,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x07,0x1F,0x3F,0x7C,0xF0,0xC0,0x00,0x00,0x00,
      0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x08,0x00,0x00,
      0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x02,0x00,
      0x00,0x00,0x00,0x80,0xE0,0x78,0x3E,0x1F,0x0F,0x03,0x01,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x06,
      0x04,0x0C,0x0C,0x1C,0x1C,0x1C,0x3C,0x38,0x38,0x78,0x78,0x78,0x78,0x78,0x78,0x7C,
      0x7C,0x7C,0x78,0x78,0x78,0x78,0x78,0x38,0x38,0x38,0x3C,0x1C,0x1C,0x0C,0x0C,0x04,
      0x04,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
#else
uint8_t * disp_buf = buffer;
uint8_t buffer[1024];
#endif

void spi_master_event_handler(nrf_drv_spi_event_t event)
{
    UNUSED_PARAMETER(event);
}

void ssd1306_spi_init(){
    uint32_t err_code = NRF_SUCCESS;

    nrf_drv_spi_config_t config =
    {
        .ss_pin       = NRF_DRV_SPI_PIN_NOT_USED,
        .irq_priority = 3, //low
        .orc          = 0xCC,
        .frequency    = NRF_DRV_SPI_FREQ_4M,
        .mode         = NRF_DRV_SPI_MODE_0,
        .bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,
    };

    config.sck_pin  = SPI_SCLK;
    config.mosi_pin = SPI_MOSI;
    config.miso_pin = NRF_DRV_SPI_PIN_NOT_USED;
    
    err_code = nrf_drv_spi_init(&m_spi_master, &config,
            spi_master_event_handler);
    APP_ERROR_CHECK(err_code);
    
    nrf_gpio_pin_set(OLED_EN);
    
}

void ssd1306_spi_uninit()
{
    nrf_gpio_pin_clear(OLED_EN);
    nrf_drv_spi_uninit(&m_spi_master);
}

void ssd1306_spi_write(uint8_t * p_tx_data, uint16_t len, _Bool dc){
    nrf_gpio_pin_clear(OLED_CS);
    nrf_gpio_pin_write(SPI_DC, dc); //data: true; command: false;
        
    uint8_t rxdata[1];
    //nrf_delay_ms(1);
    uint32_t err_code = nrf_drv_spi_transfer(&m_spi_master,
        p_tx_data, len, rxdata, 1);
    if(err_code != NRF_SUCCESS)
        APP_ERROR_CHECK(err_code);
    nrf_gpio_pin_set(OLED_CS);
}

void ssd1306_write_command(uint8_t command)
{
    ssd1306_spi_write(&command, 1, false);
    nrf_delay_ms(1);
}

void ssd1306_write_data(uint8_t * data, uint32_t len)
{
    ssd1306_spi_write(data, len, true);
}

void ssd1306_gpio_init(){
    //Init some Pin
    nrf_gpio_cfg_output(SPI_RES);
    nrf_gpio_cfg_output(SPI_DC);
    nrf_gpio_cfg_output(OLED_CS);
    
    NRF_GPIO->PIN_CNF[OLED_CS] |= 0x600; //Set pin to be "Disconnected 0 and standard 1"
    nrf_gpio_cfg_output(OLED_EN);
}

void ssd1306_chip_init(){
    //some code
    nrf_gpio_pin_clear(SPI_RES);
    nrf_delay_ms(10);
    nrf_gpio_pin_set(SPI_RES);
    
    ssd1306_write_command(SSD1306_DISPLAYOFF);          //关闭显示
    ssd1306_write_command(SSD1306_SETDISPLAYCLOCKDIV);  //设置显示
    ssd1306_write_command(0x80);                        //100帧每秒
    
    ssd1306_write_command(SSD1306_SETLOWCOLUMN);  // 0x00
    ssd1306_write_command(SSD1306_SETHIGHCOLUMN);   // 0x10

    ssd1306_write_command(SSD1306_SETMULTIPLEX);        // 0xA8
    ssd1306_write_command(0x3f);                        //64高度

    ssd1306_write_command(SSD1306_SETDISPLAYOFFSET);    // 0xD3
    ssd1306_write_command(0x0);                         // no offset
    ssd1306_write_command(SSD1306_SETSTARTLINE);  // line #0
    ssd1306_write_command(SSD1306_CHARGEPUMP);          // 0x8D
    ssd1306_write_command(0x14);

    ssd1306_write_command(SSD1306_MEMORYMODE);          // 0x20
    ssd1306_write_command(0x00);                        // 0x0 act like ks0108
    ssd1306_write_command(SSD1306_SEGREMAP | 0x1);
    ssd1306_write_command(SSD1306_COMSCANDEC);
    ssd1306_write_command(SSD1306_SETCOMPINS);          // 0xDA
    ssd1306_write_command(0x12);
    ssd1306_write_command(SSD1306_SETCONTRAST);         // 0x81
    ssd1306_write_command(0xCF);                        //使用内置电荷泵时设置为CF

    ssd1306_write_command(SSD1306_SETPRECHARGE);        // 0xd9
    ssd1306_write_command(0xF1);
    ssd1306_write_command(SSD1306_SETVCOMDETECT);       // 0xDB
    ssd1306_write_command(0x40);
    ssd1306_write_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
    ssd1306_write_command(SSD1306_NORMALDISPLAY);       // 0xA6

    ssd1306_write_command(SSD1306_DEACTIVATE_SCROLL);

    ssd1306_write_command(SSD1306_DISPLAYON);           //--turn on oled panel
}


void ssd1306_init(void){
    ssd1306_gpio_init();
    ssd1306_spi_init();
    ssd1306_chip_init();
}

void ssd1306_drawPixel(uint8_t x, uint8_t y, _Bool white){
    if(x > 128 || y > 64)
        return;
    buffer[ x + (y/8) * 128] |=  (white << (y&7));
}

void ssd1306_drawByte(uint8_t x, uint8_t y, uint8_t byte){
    if(x > 128 || y > 8)
        return;
    buffer[ x + y * 128] = byte;
}

void ssd1306_invertDisplay(_Bool i) {
  if (i) {
    ssd1306_write_command(SSD1306_INVERTDISPLAY);
  } else {
    ssd1306_write_command(SSD1306_NORMALDISPLAY);
  }
}

// startscrollright
// Activate a right handed scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
void ssd1306_startScrollRight(uint8_t start, uint8_t stop){
  ssd1306_write_command(SSD1306_RIGHT_HORIZONTAL_SCROLL);
  ssd1306_write_command(0X00);
  ssd1306_write_command(start);
  ssd1306_write_command(0X00);
  ssd1306_write_command(stop);
  ssd1306_write_command(0X00);
  ssd1306_write_command(0XFF);
  ssd1306_write_command(SSD1306_ACTIVATE_SCROLL);
}

// startscrollleft
// Activate a right handed scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
void ssd1306_startScrollLeft(uint8_t start, uint8_t stop){
  ssd1306_write_command(SSD1306_LEFT_HORIZONTAL_SCROLL);
  ssd1306_write_command(0X00);
  ssd1306_write_command(start);
  ssd1306_write_command(0X00);
  ssd1306_write_command(stop);
  ssd1306_write_command(0X00);
  ssd1306_write_command(0XFF);
  ssd1306_write_command(SSD1306_ACTIVATE_SCROLL);
}

// startscrolldiagright
// Activate a diagonal scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
void ssd1306_startScrollDiagRight(uint8_t start, uint8_t stop){
  ssd1306_write_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
  ssd1306_write_command(0X00);
  ssd1306_write_command(0x40);//height=64
  ssd1306_write_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
  ssd1306_write_command(0X00);
  ssd1306_write_command(start);
  ssd1306_write_command(0X00);
  ssd1306_write_command(stop);
  ssd1306_write_command(0X01);
  ssd1306_write_command(SSD1306_ACTIVATE_SCROLL);
}

// startscrolldiagleft
// Activate a diagonal scroll for rows start through stop
// Hint, the display is 16 rows tall. To scroll the whole display, run:
// display.scrollright(0x00, 0x0F)
void ssd1306_startScrollDiagLeft(uint8_t start, uint8_t stop){
  ssd1306_write_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
  ssd1306_write_command(0X00);
  ssd1306_write_command(0x40); //height=64
  ssd1306_write_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
  ssd1306_write_command(0X00);
  ssd1306_write_command(start);
  ssd1306_write_command(0X00);
  ssd1306_write_command(stop);
  ssd1306_write_command(0X01);
  ssd1306_write_command(SSD1306_ACTIVATE_SCROLL);
}

void ssd1306_stopScroll(void){
  ssd1306_write_command(SSD1306_DEACTIVATE_SCROLL);
}

void ssd1306_display(void) {
    uint16_t i;
    ssd1306_write_command(SSD1306_COLUMNADDR);
    ssd1306_write_command(0);   // Column start address (0 = reset)
    ssd1306_write_command(0x7F); // Column end address (127 = reset)

    ssd1306_write_command(SSD1306_PAGEADDR);
    ssd1306_write_command(0); // Page start address (0 = reset)
    ssd1306_write_command(7); // Page end address
    for(i=0;i<1024;i+=64){ 
        ssd1306_write_data(&buffer[i], 64);
        nrf_delay_ms(1);
    }
    
}

void ssd1306_clearDisplay(void)
{
    memset(buffer, 0, 1024);
}

void ssd1306_displayOff(void)
{
    ssd1306_write_command(SSD1306_DISPLAYOFF);          //关闭显示
    ssd1306_write_command(SSD1306_CHARGEPUMP);          // 0x8D
    ssd1306_write_command(0x10);
}

void ssd1306_displayOn(void)
{
    ssd1306_write_command(SSD1306_CHARGEPUMP);          // 0x8D
    ssd1306_write_command(0x14);
    ssd1306_write_command(SSD1306_DISPLAYON);          //关闭显示
}


